import { RequestResponse } from 'umi-request';
import jsonpath from 'jsonpath';
import lodash from 'lodash';
import { request, RequestOptions, ResError } from './request';
import { TypeEnum, variableTypeOf } from './typeof';
import { hasValue } from './utils';

/** 服务端通用数据 */
interface GeneralData {
  [key: string]: any;
}

/** 排序项 */
interface OrderItem {
  /** 排序列 */
  column: string;
  /** 排序类型, true:ASC; false:DESC */
  asc: boolean;
}

/** 服务端表格数据 */
interface TableData<T = any> {
  /** 当前页数据 */
  records: T[];
  /** 数据总量 */
  total: number;
  /** 当前页 */
  current: number;
  /** 页大小 */
  size?: number;
  /** 当前分页总页数 */
  pages?: number;
  /** 是否进行count查询 */
  searchCount?: boolean;
  /** 排序规则 */
  orders?: OrderItem[];
}

/** 获取服务端数据配置 */
interface ServerDataConfig<T = any> {
  /** 请求接口地址 */
  url: string;
  /** HTTP request 配置 */
  options?: RequestOptions;
  /** 是否默认加载数据 */
  initLoadData?: boolean;
  /** 请求之前的拦截 */
  interceptor?: (url: string, options: RequestOptions) => false | { url: string; options?: RequestOptions } | void;
  /** 请求开始前回调 */
  onStart?: () => void;
  /** 请求完成后回调 */
  onCompleted?: () => void;
  /** 请求发生错误回调 */
  onError?: (resData: any, error: ResError) => void;
  /** 请求成功回调 */
  onSuccess?: (data: T, response: RequestResponse) => void;
  /** 响应json data中取Data数据 */
  getData?: (resData: any, response: RequestResponse) => T;
  /** 根据JsonPath从响应json data中取Data数据 */
  dataJsonPath?: string;
}

/** ServerDataConfig默认值 */
const ServerDataDefaultConfig: Partial<ServerDataConfig> = {
  initLoadData: true,
  dataJsonPath: '$',
};

/** 获取服务端表格数据配置 */
interface ServerTableDataConfig<RecordType = any> extends ServerDataConfig<TableData<RecordType>> {
  /** 是否启用分页，默认：true */
  enablePagination?: boolean;
  /** 设置页面大小请求参数名称，默认：pageSize */
  pageSizeParamName?: string;
  /** 设置当前页请求参数名称，默认：pageNo */
  pageNoParamName?: string;
  /** 根据JsonPath获取"当前页数据"($.records) */
  dataJsonPath?: string;
  /** 根据JsonPath获取"数据总量"($.total) */
  totalJsonPath?: string;
  /** 根据JsonPath获取"当前页"($.current) */
  currentJsonPath?: string;
  /** 根据JsonPath获取"页大小"($.size) */
  sizeJsonPath?: string;
  /** 根据JsonPath获取"当前分页总页数"($.pages) */
  pagesJsonPath?: string;
  /** 根据JsonPath获取"是否进行count查询"($.searchCount) */
  searchCountJsonPath?: string;
  /** 根据JsonPath获取"排序规则"($.orders) */
  ordersJsonPath?: string;
}

/** ServerTableDataConfig默认值 */
const ServerTableDataDefaultConfig: Partial<ServerTableDataConfig> = {
  initLoadData: true,
  enablePagination: true,
  pageSizeParamName: 'pageSize',
  pageNoParamName: 'pageNo',
  dataJsonPath: '$.records',
  totalJsonPath: '$.total',
  currentJsonPath: '$.current',
  sizeJsonPath: '$.size',
  pagesJsonPath: '$.pages',
  searchCountJsonPath: '$.searchCount',
  ordersJsonPath: '$.orders',
};

/**
 * 请求前拦截处理
 * @param config    ServerDataConfig配置
 * @param callback  请求完成或请求取消后的回调
 */
const interceptorFuc = <T>(config: ServerDataConfig<T>, callback: () => void): Pick<ServerDataConfig<T>, 'url' | 'options'> | false => {
  let { url, options } = config;
  const { interceptor } = config;
  // 请求前拦截 - 修改请求参数
  if (interceptor instanceof Function) {
    const res = interceptor(url, options ?? {});
    if (res === false) {
      if (variableTypeOf(callback) === TypeEnum.function) {
        // 请求取消
        callback();
      }
      return false;
    }
    if (res && variableTypeOf(res) === TypeEnum.object) {
      const reqCfg: any = res as any;
      if (reqCfg.url) url = reqCfg.url;
      if (reqCfg.options) options = reqCfg.options;
    }
  }
  return { url, options };
};

/**
 * 请求发生错误的处理
 * @param config  ServerDataConfig配置
 * @param error   请求错误信息
 */
const onErrorFuc = <T>(config: ServerDataConfig<T>, error: ResError): void => {
  const { onError } = config;
  if (onError instanceof Function) {
    onError(error.data, error);
  }
};

/**
 * 请求完成后的处理
 * @param config    ServerDataConfig配置
 * @param data      请求响应数据
 * @param callback  请求完成或请求取消后的回调
 */
const onCompletedFuc = <T>(config: ServerDataConfig<T>, data: T, callback: (data: T) => void): void => {
  const { onCompleted } = config;
  if (callback instanceof Function) {
    callback(data);
  }
  if (onCompleted instanceof Function) {
    onCompleted();
  }
};

/**
 * 根据 jsonPath 获取数据
 * @param data      原始数据
 * @param jsonPath  JsonPath
 */
const getValueByJsonPath = (data: any, jsonPath?: string): any => {
  let res: any;
  if (jsonPath && lodash.trim(jsonPath).length > 0) {
    const resDataArray: any[] = jsonpath.query(data, jsonPath);
    if (resDataArray && resDataArray.length >= 1) {
      res = resDataArray[0];
    }
  }
  return res;
};

const getNumberByJsonPath = (data: any, jsonPath?: string): number | void => {
  let num = getValueByJsonPath(data, jsonPath);
  // if (tmpRes) total = tmpRes;
  if (hasValue(num) && variableTypeOf(num) === TypeEnum.string) {
    num = lodash.toNumber(num);
  }
  return num;
};
const getBooleanByJsonPath = (data: any, jsonPath?: string): boolean | void => {
  let bool = getValueByJsonPath(data, jsonPath);
  // if (tmpRes) total = tmpRes;
  if (hasValue(bool) && variableTypeOf(bool) !== TypeEnum.boolean) {
    bool = !!bool;
  }
  return bool;
};

/**
 * 根据配置获取服务端数据
 * @param config    ServerDataConfig配置
 * @param callback  请求完成或请求取消后的回调
 */
const getServerData = <T = any>(config: ServerDataConfig<T>, callback: (data?: T) => void): Promise<void> => {
  let { url, options } = config;
  const { onStart, onSuccess, getData, dataJsonPath } = config;
  // 请求前拦截 - 修改请求参数
  const isReturn = interceptorFuc<T>(config, callback);
  if (isReturn === false) {
    return Promise.resolve();
  } else {
    if (isReturn.url) url = isReturn.url;
    if (isReturn.options) options = isReturn.options;
  }
  // 开始请求
  if (onStart instanceof Function) {
    onStart();
  }
  let data: T | undefined;
  // 发送请求
  return request(url, { ...options, getResponse: true })
    .then((response: RequestResponse) => {
      // 请求成功
      // console.log("then --> ", response);
      data = response.data;
      // 获取数据
      if (getData instanceof Function) {
        data = getData(data, response);
      } else if (dataJsonPath) {
        const resDataArray: any[] = jsonpath.query(data, dataJsonPath);
        data = undefined;
        if (resDataArray && resDataArray.length >= 1) {
          data = resDataArray[0];
        }
      }
      if (onSuccess instanceof Function) {
        onSuccess(data as T, response);
      }
    })
    .catch((error: ResError) => {
      // 请求发生错误
      // console.log("catch --> ", error.response);
      onErrorFuc<T>(config, error);
    })
    .finally(() => {
      // 请求完成后
      // console.log("finally --> ");
      onCompletedFuc<T>(config, <T>data, callback);
    });
};

/**
 * 根据配置获取服务端表格数据
 * @param config    ServerTableDataConfig配置
 * @param callback  请求完成或请求取消后的回调
 */
const getServerTableData = <T = any>(config: ServerTableDataConfig<T>, callback: (data?: TableData<T>) => void): Promise<void> => {
  let { url, options } = config;
  const { onStart, onSuccess, getData, dataJsonPath, totalJsonPath, currentJsonPath, sizeJsonPath, pagesJsonPath, searchCountJsonPath, ordersJsonPath } = config;
  // 请求前拦截 - 修改请求参数
  const isReturn = interceptorFuc<TableData<T>>(config, callback);
  if (isReturn === false) {
    return Promise.resolve();
  } else {
    if (isReturn.url) url = isReturn.url;
    if (isReturn.options) options = isReturn.options;
  }
  // 开始请求
  if (onStart instanceof Function) {
    onStart();
  }
  let data: TableData<T> | undefined;
  // 发送请求
  return request(url, { ...options, getResponse: true })
    .then((response: RequestResponse) => {
      // 请求成功
      // console.log("then --> ", response);
      data = response.data;
      // 获取数据
      if (getData instanceof Function) {
        data = getData(data, response);
      } else {
        let records: T[] = [];
        let total: number = 0;
        let current: number = 0;
        let size: number | undefined;
        let pages: number | undefined;
        let searchCount: boolean | undefined;
        let orders: OrderItem[] | undefined;
        // 取值逻辑
        let tmpRes = getValueByJsonPath(data, dataJsonPath);
        if (tmpRes) records = tmpRes;
        // total
        tmpRes = getNumberByJsonPath(data, totalJsonPath);
        if (tmpRes) total = tmpRes;
        // current
        tmpRes = getNumberByJsonPath(data, currentJsonPath);
        if (tmpRes) current = tmpRes;
        // size
        tmpRes = getNumberByJsonPath(data, sizeJsonPath);
        if (tmpRes) size = tmpRes;
        // pages
        tmpRes = getNumberByJsonPath(data, pagesJsonPath);
        if (tmpRes) pages = tmpRes;
        // searchCount
        tmpRes = getBooleanByJsonPath(data, searchCountJsonPath);
        if (tmpRes) searchCount = tmpRes;
        // orders
        tmpRes = getValueByJsonPath(data, ordersJsonPath);
        if (tmpRes) orders = tmpRes;
        data = { records, total, current };
        if (hasValue(size)) data.size = size;
        if (hasValue(pages)) data.pages = pages;
        if (hasValue(searchCount)) data.searchCount = searchCount;
        if (hasValue(orders)) data.orders = orders;
      }
      if (onSuccess instanceof Function) {
        onSuccess(data as TableData<T>, response);
      }
    })
    .catch((error: ResError) => {
      // 请求发生错误
      // console.log("catch --> ", error.response);
      onErrorFuc<TableData<T>>(config, error);
    })
    .finally(() => {
      // 请求完成后
      // console.log("finally --> ");
      onCompletedFuc<TableData<T>>(config, <TableData<T>>data, callback);
    });
};

export { GeneralData, TableData, ServerDataConfig, ServerTableDataConfig, getServerData, ServerDataDefaultConfig, getServerTableData, ServerTableDataDefaultConfig };
